package com.lowkey.proxy;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.xml.crypto.Data;

import net.sf.cglib.proxy.MethodProxy;

import com.lowkey.dataSource.DBControl;
import com.lowkey.sqlTools.LowkeyDetachedCriteria;
import com.lowkey.tableInfo.Id;
import com.lowkey.tableInfo.ManyToOne;
import com.lowkey.tableInfo.Property;
import com.lowkey.tableInfo.TableInfo;
import com.lowkey.tools.Constant;

public class CGLIBLazyInitializerImpl implements LazyInitializer {

	private Class c;
	private Serializable id;
	private LowkeyDetachedCriteria deta;
	private Object mainObj=null;
	private Class mainClazz = null;
	private String condition;
	private DBControl db =null;
	private List<ManyToOne> manyList =null;

	@Override
	public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		//首先判断对哪个方法进行拦截.
		String methodNames = proxy.getSuperName();
		String[] methods = methodNames.split("\\$");
		String realMethodName="";
		String attributeName = "";
		if(methods.length>0){
			realMethodName = methods[1];
		}
		
		attributeName=realMethodName.substring(3,4).toLowerCase()+realMethodName.substring(4);
		for(ManyToOne m : manyList){
			if(m.getManyName().equals(attributeName)){
 				setValue(m.getManyClass(),attributeName);
			}
		}
		//如果是常规方法,那么,查询数据库.
		if(null==mainObj){
			setValue();
		}
		Object result = getValueByObject(attributeName,mainObj);
		return result;
	}

	private void setManyList(){
		if(Constant.TABLEMAP==null){
			new DBControl();
		}
		this.manyList = Constant.TABLEMAP.get(c.getName()).getManyList();
	}
	
	private Object getValueByObject(String name, Object o) {
		Field f = null;// 通过反射获得 类的字段名称！
		Object value = null;//
		try {
			f = o.getClass().getDeclaredField(name);
			f.setAccessible(true);
			value = f.get(o);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return value;
	}
	private void setValue(){
		db= new DBControl();
		TableInfo table = Constant.TABLEMAP.get(c.getName());
		String sql="select * from "+ table.getTableName()+" where ";
		if(id!=null){
			sql+=table.getId().getColumn()+"="+id;
		}else if (deta!=null){
			sql=deta.getSql();
		}else if (condition!=null){
			sql+=condition;
		}
		System.out.println(sql);
		ResultSet rs = db.getData(sql);
		//准备实体->表信息
		Id id = table.getId();
		List<Property> pList = table.getPropertys();
		List<ManyToOne> manyList=table.getManyList();
		try {
			while(rs.next()){
				mainClazz = Class.forName(table.getClassName());
				Object mainObject = mainClazz.newInstance();
				
				Field mainObject_Id_field = mainClazz.getDeclaredField(id.getName());
				Class mainObject_Id_Type = mainObject_Id_field.getType();
				Method mainObject_Id_Method = mainClazz.getDeclaredMethod("set"+id.getName().substring(0,1).toUpperCase()+id.getName().substring(1),mainObject_Id_Type);
				mainObject_Id_Method.invoke(mainObject, rs.getObject(table.getTableName()+"."+id.getColumn()));
				if(pList!=null){
					for(Property p:pList){
						Field pf  = mainClazz.getDeclaredField(p.getName());
						Class pc = pf.getType();
						Method pMethod = mainClazz.getDeclaredMethod("set"+p.getName().substring(0,1).toUpperCase()+p.getName().substring(1),pc);
						pMethod.invoke(mainObject,rs.getObject(table.getTableName()+"."+p.getColumn()));
					}
				}
				if(manyList != null){
					for(ManyToOne m : manyList){
						Class manyClass = Class.forName(m.getManyClass());
						//new 一个many对象.例如:new Style()
						Object manyObject = manyClass.newInstance();
						//id赋值 例:将styleId 放进 sytle中		
						Field manyObject_Id_Field = manyClass.getDeclaredField(m.getManyColumn());
						Class manyObject_Id_Type = manyObject_Id_Field.getType();
						Method manyObject_Id_Method = manyClass.getDeclaredMethod("set"+m.getManyColumn().substring(0,1).toUpperCase()+m.getManyColumn().substring(1), manyObject_Id_Type);
						
						manyObject_Id_Method.invoke(manyObject, rs.getObject(m.getManyColumn()));
						//再将stytle对象放进book中.
						Method mChildSetParent = mainClazz.getDeclaredMethod("set"+m.getManyName().substring(0,1).toUpperCase()+m.getManyName().substring(1), manyClass);
						mChildSetParent.invoke(mainObject,manyObject);
					}
				}
				this.mainObj = mainObject;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			db.close();
		}
		
	}
	
	//二次懒加载
	private void setValue(String manyClassName,String manyName){
		db = new DBControl();
		TableInfo manyTable = Constant.TABLEMAP.get(manyClassName);
 
		Id manyObject_id = manyTable.getId();
		Object manyObject = getValueByObject(manyName, mainObj);//获得style对象
		Object manyObject_IdValue = getValueByObject(manyObject_id.getName(), manyObject);
		
		String sql ="select * from "+ manyTable.getTableName()+" where " + manyObject_id.getColumn()+"="+ manyObject_IdValue;
		System.out.println(sql);
		ResultSet rs = db.getData(sql);
		
		List<Property> manyPropertyList = manyTable.getPropertys();
		try {
			Class manyClass = Class.forName(manyClassName);
			while (rs.next()){
				if(manyPropertyList!=null){
					for(Property p:manyPropertyList){
						Field pf  = manyClass.getDeclaredField(p.getName());
						Class pc = pf.getType();
						Method pMethod = manyClass.getDeclaredMethod("set"+p.getName().substring(0,1).toUpperCase()+p.getName().substring(1),pc);
						pMethod.invoke(manyObject,rs.getObject(manyTable.getTableName()+"."+p.getColumn()));
					}
				}
				//把查到style放进去
				Method mChildSetParent = mainClazz.getDeclaredMethod("set"+manyName.substring(0,1).toUpperCase()+manyName.substring(1), manyClass);
				mChildSetParent.invoke(mainObj,manyObject);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			db.close();
		}
		 
	}
	
	public void setManyList(List<ManyToOne> manyList) {
		this.manyList = manyList;
	}
	
	@Override
	public void load(Class c, Serializable id) {
		this.c = c;
		this.id = id;
		setManyList();
	}

	@Override
	public void load(Class c, LowkeyDetachedCriteria deta) {
		this.c = c;
		this.deta = deta;
		setManyList();
	}

	@Override
	public void load(Class c, String condtion) {
		this.c = c;
		this.condition = condition;
		setManyList();
	}

}
